﻿using Microsoft.Xna.Framework.Input;
using System;

namespace SpiritEngine
{
    // An input device that manages the Keyboard and KeyboardState
    public class CID_Keyboard : AC_InputDevice<KeyboardState>
    {
        // MEMBER VARIABLES
        // ------------------------------------------------------------------------------------------------------------------------

        // The last and current KeyboardStates
        KeyboardState last;
        KeyboardState current;

        Keys[] currentKeys;



        // CONSTRUCTORS
        // ------------------------------------------------------------------------------------------------------------------------

        // Constructor sets up the current state and updates for the first time
        public CID_Keyboard()
        {
            current = Keyboard.GetState();
            Update();

        } // end CID_Keyboard.CID_Keyboard()



        // PRIVATE/PROTECTED METHODS
        // ------------------------------------------------------------------------------------------------------------------------



        // METHODS
        // ------------------------------------------------------------------------------------------------------------------------

        public override void Update()
        {
            // Set the last state to the current one and update the current state
            last = current;
            current = Keyboard.GetState();

            // Set the currently pressed keys to the keys defined in the current state
            currentKeys = current.GetPressedKeys();

            // For every key on the keyboard...
            foreach (Keys key in Utility.GetEnumValues<Keys>())
            {
                // If it is a new key press (this is the first frame it is down),
                // trigger the corresponding event
                if (WasKeyPressed(key))
                {
                    if (KeyPressed != null)
                        KeyPressed(this, new InputDeviceEventArgs<Keys,KeyboardState>(key, this));
                }
                
                // If it was just released (this is the first frame it is up),
                // trigger the corresponding event
                if (WasKeyReleased(key))
                {
                    if (KeyReleased != null)
                        KeyReleased(this, new InputDeviceEventArgs<Keys,KeyboardState>(key, this));
                }

                // If it has been held (it has been down for more than one frame),
                // trigger the corresponding event
                if (WasKeyHeld(key))
                {
                    if (KeyHeld != null)
                        KeyHeld(this, new InputDeviceEventArgs<Keys,KeyboardState>(key, this));
                }


            } // end foreach

        } // end CID_Keyboard.Update()

        // Whether the specified key is currently down
        public bool IsKeyDown(Keys Key)
        {
            return current.IsKeyDown(Key);

        } // end CID_Keyboard.IsKeyDown(Keys)

        // Whether the specified key is currently up
        public bool IsKeyUp(Keys Key)
        {
            return current.IsKeyUp(Key);

        } // end CID_Keyboard.IsKeyUp(Keys)

        // Whether the specified key is down for the first time this frame
        public bool WasKeyPressed(Keys Key)
        {
            if (last.IsKeyUp(Key) && current.IsKeyDown(Key))
                return true;

            return false;

        } // end CID_Keyboard.WasKeyPressed(Keys)

        // Whether he specified key is up for the first time thi sframe
        public bool WasKeyReleased(Keys Key)
        {
            if (last.IsKeyDown(Key) && current.IsKeyUp(Key))
                return true;

            return false;

        } // end CID_Keyboard.WasKeyReleased(Keys)

        // Whether the specified key has been down for more than one frame
        public bool WasKeyHeld(Keys Key)
        {
            if (last.IsKeyDown(Key) && current.IsKeyDown(Key))
                return true;

            return false;

        } // end CID_Keyboard.WasKeyHeld(Keys)



        // DEBUG METHODS
        // ------------------------------------------------------------------------------------------------------------------------

#if (DEBUG)
        // put all debug methods in here...
#endif


        // PROPERTIES
        // ------------------------------------------------------------------------------------------------------------------------

        // State property
        public override KeyboardState State
        {
            get
            {
                return current;
            }
        } // end property State

        // PressedKeys property
        public Keys[] PressedKeys
        {
            get
            {
                return currentKeys;
            }
        } // end property PressedKeys



        // EVENTS
        // ------------------------------------------------------------------------------------------------------------------------

        // Events for when a button is pressed, released, or held
        public event InputEventHandler<Keys, KeyboardState> KeyPressed;
        public event InputEventHandler<Keys, KeyboardState> KeyReleased;
        public event InputEventHandler<Keys, KeyboardState> KeyHeld;



    } // end class CID_Keyboard

} // end namespace SpiritEngine
